package com.cf.base.mvp.mvp.proxy;

import androidx.annotation.Nullable;

import com.cf.base.mvp.mvp.BasePresenter;
import com.cf.base.mvp.mvp.IBaseView;
import com.cf.base.mvp.mvp.IPresenter;
import com.cf.base.mvp.mvp.annotation.FunPresenter;
import com.cf.base.mvp.mvp.annotation.Presenter;
import com.cf.base.mvp.mvp.execptions.MvpException;
import com.cf.base.mvp.log.LogUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yangji
 */
public abstract class ProxyImpl<P extends IPresenter> implements IProxy {

    private List<IPresenter> mProxyPresenters;
    private List<IPresenter> mPresenters;

    //通过头部产生的代理注解
    private P mProxyPresenter;
    private IBaseView mBaseView;

    public P getMainPresenter() {
        return mProxyPresenter;
    }

    protected ProxyImpl() {
        this.mProxyPresenters = new ArrayList<>();
        this.mPresenters = new ArrayList<>();
    }

    @Override
    public void bindPresenter(IBaseView iBaseView) {
        this.mBaseView = iBaseView;
        mProxyPresenter = initPresenter(iBaseView);
        mProxyPresenters.add(mProxyPresenter);
        initChildPresenter(iBaseView);
    }

    //获取所有扩展的 Presenter
    private void initChildPresenter(IBaseView iBaseView) {
        //获得已经申明的变量，包括私有的
        Field[] fields = iBaseView.getClass().getDeclaredFields();
        for (Field field : fields) {
            FunPresenter cp = field.getAnnotation(FunPresenter.class);
            if (cp == null) {
                continue;
            }
            Class<? extends BasePresenter> clsP = cp.value();
            Class fieldType = field.getType();
            IPresenter presenter = createPresenter(iBaseView, fieldType, clsP);
            try {
                field.setAccessible(true);
                field.set(iBaseView, presenter);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            //做好回收处理
            mProxyPresenters.add(presenter);
        }
    }

    @Override
    public void unBindPresenter() {
        for (IPresenter presenter : mProxyPresenters) {
            presenter.unBindView();
        }
        for (IPresenter presenter : mPresenters) {
            mBaseView.getLifecycle().removeObserver(presenter);
        }
        mProxyPresenters.clear();
        mProxyPresenters = null;
    }


    @SuppressWarnings({"unchecked"})
    private P initPresenter(IBaseView iBaseView) {
        Presenter pClass = iBaseView.getClass().getAnnotation(Presenter.class);

        Class<? extends BasePresenter> classValue = null;

        if (pClass != null) {
            classValue = pClass.value();
        }

        //下面用于做统计或者没有实现 Presenter 暂时使用
        ParameterizedType type = (ParameterizedType) iBaseView.getClass().getGenericSuperclass();
        Class fieldType = null;
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            if (types.length > 0) {
                fieldType = ((Class) types[0]);
            }
        }
        return (P) createPresenter(iBaseView, fieldType, classValue);
    }

    @SuppressWarnings({"unchecked"})
    private <T> T createProxyPresenter(IPresenter presenter, Class<T> tClass) {
        return (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{tClass}, (proxy, method, args) -> {
            if (presenter == null) {
                LogUtils.e("统计:", "未实现", "Presenter = ", tClass.getSimpleName(), "方法 = ", method.getName());
                return null;
            }
            LogUtils.d("统计:", "调用方法前", "Presenter = ", presenter.getClass().getSimpleName(), "方法 = ", method.getName());
            Object object = method.invoke(presenter, args);
            LogUtils.d("统计:", "调用方法完成", "Presenter = ", presenter.getClass().getSimpleName(), "方法 = ", method.getName());
            return object;
        });
    }

    @SuppressWarnings({"unchecked"})
    private IPresenter createPresenter(IBaseView iBaseView, Class fieldType, Class<? extends BasePresenter> classValue) {
        IPresenter presenter = null, proxyPresenter = null;
        validation(fieldType, classValue);

        //创建 Presenter
        if (classValue != null) {
            try {
                presenter = classValue.newInstance();
                presenter.bindView(iBaseView);
                mPresenters.add(presenter);
                iBaseView.getLifecycle().addObserver(presenter);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //创建代理Presenter
        if (fieldType != null) {
            proxyPresenter = (IPresenter) createProxyPresenter(presenter, fieldType);
        }

        return (proxyPresenter == null ? presenter : proxyPresenter);
    }

    //不期望大家写代码
    private void validation(@Nullable Class<?> fieldType, @Nullable Class annotationsType) {

        if (fieldType != null) {
            if (!IPresenter.class.isAssignableFrom(fieldType)) {
                throw new MvpException("当前返回值 不是 IPresenter 接口类");
            }

            if (BasePresenter.class.isAssignableFrom(fieldType)) {
                throw new MvpException("更希望大家是面向接口编程，而不是面向具体类编程");
            }
        }

        if (fieldType != null && annotationsType != null) {
            if (!fieldType.isAssignableFrom(annotationsType)) {
                throw new MvpException(String.format("将 %s 转换为 %s 出现错误", annotationsType.getName(), fieldType.getName()));
            }
        }

    }


}
